package com.huilian.iotbox.client.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.huilian.iotbox.aliyun.service.PubService;
import com.huilian.iotbox.client.dao.DeviceDao;
import com.huilian.iotbox.client.dao.OrderDao;
import com.huilian.iotbox.client.producer.RabbitProducer;
import com.huilian.iotbox.client.service.*;
import com.huilian.iotbox.data.cmd.*;
import com.huilian.iotbox.data.common.RedisKey;
import com.huilian.iotbox.data.common.ServerResponse;
import com.huilian.iotbox.data.config.AgencyConfig;
import com.huilian.iotbox.data.config.MiddlewareConfig;
import com.huilian.iotbox.data.constants.DelayConstants;
import com.huilian.iotbox.data.controller.ControllerException;
import com.huilian.iotbox.data.dto.*;
import com.huilian.iotbox.data.enums.*;
import com.huilian.iotbox.data.po.*;
import com.huilian.iotbox.data.service.*;
import com.huilian.iotbox.data.utils.*;
import com.huilian.iotbox.data.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author 谢洛涛
 * @date 2021/1/9 11:42
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    private static Integer adminAgencyId = 1;
    @Autowired
    private OrderDao orderDao;
    @Value("${huilian.iot.productKey}")
    private String productKey;
    @Autowired
    private DeviceDao deviceDao;
    @Autowired
    private PubService pubService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private AgencyConfig agencyConfig;
    @Autowired
    private AgencyService agencyService;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private RabbitProducer rabbitProducer;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private BlueToothPubService blueToothPubService;
    @Autowired
    private SystemConfigService systemConfigService;
    @Autowired
    private MerchantStoreService merchantStoreService;
    @Autowired
    private ErrorLogCommonService errorLogCommonService;
    @Autowired
    private OrderCommissionService orderCommissionService;
    @Autowired
    private DisplayRackItemService displayRackItemService;
    @Autowired
    private MemberStoreBalanceService memberStoreBalanceService;
    @Autowired
    private RedisTemplate<String, Serializable> redisCacheTemplate;

    @Override
    public Integer add(OrderDto orderDto) {
        return orderDao.add(orderDto);
    }

    /**
     * 订单回调
     */
    @Override
    public String payNotice(HttpServletRequest request) throws Exception {
        BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String tempLine = "";
        StringBuffer resultBuffer = new StringBuffer();
        while ((tempLine = reader.readLine()) != null) {
            resultBuffer.append(tempLine).append(System.getProperty("line.separator"));
        }
        String response = resultBuffer.toString();
        log.info("支付回调通知报文{}", response);
        final Map<String, Object> res = HttpUtils.getResultData(response);
        Map<String, String> result = (Map<String, String>) res.get("data");
        String attach = result.get("attach");
        JSONObject attachJsonObject = new JSONObject();
        if (ObjectUtils.isEmpty(attach)) {
            log.info("支付回调通知报文,attach为空{}", attach);
        } else {
            attachJsonObject = JSONObject.parseObject(attach);
        }
        log.info("支付回调通知报文,attach{}", attach);
        String outTradeNo = result.get("outTradeNo");
        String channelType = result.get("channelType");
        String totalAmount = result.get("totalAmount");
        if (StringUtils.isEmpty(outTradeNo) || StringUtils.isEmpty(totalAmount)) {
            throw new ControllerException("返回参数有误!");
        }
//        Order order = new Order();
        //加完用户余额后修改订单状态,并显示支付方式
        if ("ALI".equals(channelType)) {
            channelType = "01";
        } else {
            channelType = "02";
        }
        PayNotice payNotice = new PayNotice();
        payNotice.setOutTradeNo(outTradeNo);
        payNotice.setChannelType(channelType);
        payNotice.setTotalAmount(totalAmount);
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        payNotice.setGmtPayment(df.parse(result.get("gmtPayment")));
        String notifyTime = result.get("notifyTime");
        if (!StringUtils.isEmpty(notifyTime)) {
            payNotice.setNotifyTime(df.parse(notifyTime));
        }
        payNotice.setBankType(result.get("bankType"));
        payNotice.setPayChannelOrderNo(result.get("payChannelOrderNo"));
        payNotice.setMerchantOrderNo(result.get("merchantOrderNo"));
        payNotice.setOpenId(result.get("openId"));

        payNotice.setBuyerUserId(result.get("buyerUserId"));

        payNotice.setOrderNo(result.get("orderNo"));
        if (!ObjectUtils.isEmpty(attachJsonObject.get("privateDomainOperationScoreId"))) {
            payNotice.setPrivateDomainOperationScoreId(attachJsonObject.getInteger("privateDomainOperationScoreId"));
        }
        if (!StringUtils.isEmpty(attachJsonObject.getInteger("function"))) {
            payNotice.setFunction(attachJsonObject.getInteger("function"));
        }
        if (!StringUtils.isEmpty(attachJsonObject.getString("payNo"))) {
            payNotice.setPayNo(attachJsonObject.getString("payNo"));
        }
        CorrelationData correlationData = new CorrelationData(payNotice.getOutTradeNo());
        rabbitTemplate.convertAndSend("iotBox-order-notice", "iotBox-order-notice.iotBoxOrderNotice", payNotice, correlationData);
        log.info("发送地址{}", rabbitTemplate.getRoutingKey());
        log.info("--------发送MQ成功！--------时间{}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        return "SUCCESS";
    }

    /**
     * 查询订单信息
     */
    @Override
    public synchronized Order findByOutTradeNoAndTotalAmount(String outTradeNo, BigDecimal amount) {
        return orderDao.findByOutTradeNoAndTotalAmount(outTradeNo, amount);
    }


    /**
     * 格式化订单信息
     *
     * @param payNotice
     * @param order
     * @return
     */
    @Override
    public Order convertByPayNotice(PayNotice payNotice, Order order) {
        order.setChannelType(payNotice.getChannelType());
        order.setGmtPayment(payNotice.getGmtPayment());
        order.setNotifyTime(payNotice.getNotifyTime());
        order.setBankType(payNotice.getBankType());
        order.setPayChannelOrderNo(payNotice.getPayChannelOrderNo());
        order.setMerchantOrderNo(payNotice.getMerchantOrderNo());
        // 注释掉,因为回调过来的openid和我们传递过去的openid不一样,直接查数据的openid就行了
//        order.setOpenId(payNotice.getOpenId());
        order.setBuyerUserId(payNotice.getBuyerUserId());
        order.setOrderNo(payNotice.getOrderNo());
        order.setStatus(OrderStatusEnum.SUCCESS.getCode());
        return order;
    }

    @Override
    public Integer updateOrder(Order order) {
        return orderDao.updateOrder(order);
    }

    /**
     * 处理订单支付完成回调业务
     *
     * @param order
     * @param payNotice
     */
    @Override
    public synchronized void handleOrder(Order order, PayNotice payNotice) throws InterruptedException {

        order = this.convertByPayNotice(payNotice, order);

        this.orderHandlingCharge(order);

        if (MchTypeEnum.OFFLINE_COLLECTION_CODE.getCode().equals(order.getMchType())) {
            memberStoreBalanceService.updateOrderRecord(order);
            log.info(order.getOutTradeNo() + "线下收款订单处理完成");

            if (!StringUtils.isEmpty(order.getMemberId())) {
                merchantStoreService.setMemberRisk(order.getMemberId(), order.getMerchantStoreId(), order.getGmtPayment(), order.getTotalAmount());
            }
            return;
        }

        final DeviceVo device = deviceService.findOneDeviceByDeviceNo(order.getDeviceNo());
        final SystemConfig systemConfig = systemConfigService.findOneSystemConfigById(1);
        if (DeviceTypeEnum.VENDING_MACHINE.getCode().equals(order.getDeviceTypeId())
                || DeviceTypeEnum.SCREEN_VENDING_MACHINE.getCode().equals(order.getDeviceTypeId())
                || DeviceTypeEnum.OPEN_DOOR_VENDING_MACHINE.getCode().equals(order.getDeviceTypeId())
                || DeviceTypeEnum.BLEND_VENDING_MACHINE.getCode().equals(order.getDeviceTypeId())) {
            List<OrderItem> list = orderItemService.getOrderItemById(order.getId());
            try {
                if(!StringUtils.isEmpty(device.getPayLimitTime())) {
                    String memberPayDetailKey = String.format(RedisKey.LIMITATION_SIMULTANEOUS_PAYMENT_VENDING_MACHINE, device.getId());
                    redisCacheTemplate.opsForValue().set(memberPayDetailKey, 1, device.getPayLimitTime(), TimeUnit.SECONDS);
                }
                list.get(0).setStatus(OrderStatusEnum.SUCCESS.getCode());
                orderItemService.update(list.get(0));
            } catch (Exception e) {
                log.info("修改售货机订单详情出错");
            }
            List<OrderItem> orderItemList = new ArrayList<>();
            List<OrderItem> latticeOrderItemList = new ArrayList<>();
            for (OrderItem orderItem : list) {
                DisplayRackItemDto displayRackItemDto = new DisplayRackItemDto();
                displayRackItemDto.setDeviceId(orderItem.getDeviceId());
                displayRackItemDto.setHierarchy(orderItem.getHierarchy());
                displayRackItemDto.setFreightLane(orderItem.getFreightLane());
                displayRackItemDto.setIsDelete(false);

                DisplayRackItemVo displayRackItemVo = displayRackItemService.findDisplayRackItemByDeviceId(displayRackItemDto);
                if (!StringUtils.isEmpty(displayRackItemVo.getDeviceTypeId())) {
                    if (DeviceTypeEnum.OPEN_DOOR_VENDING_MACHINE.getCode().equals(displayRackItemVo.getDeviceTypeId())) {
                        latticeOrderItemList.add(orderItem);
                    } else {
                        orderItemList.add(orderItem);
                    }
                } else {
                    // 这里的判断是为了兼容之前的设备
                    if (DeviceTypeEnum.OPEN_DOOR_VENDING_MACHINE.getCode().equals(order.getDeviceTypeId())) {
                        latticeOrderItemList.add(orderItem);
                    } else {
                        orderItemList.add(orderItem);
                    }
                }
                updateStock(displayRackItemVo, orderItem.getNum());


            }
            String command = null;
            Boolean bool = true;
            Map<String, String> delayMap = new HashMap<>();
            if (!StringUtils.isEmpty(device.getLoginId()) && device.getLoginId().equals(VendingMachineTypeEnum.ELECTROMAGNETIC_LOCK.getCode())) {
                // 有开门的格子机的在外面，设备没办法远程升级，只能兼容
                command = PositiveDataFrameCMD.penetrate(VendmachPositiveDataFrameCMD.LatticeShipment(latticeOrderItemList.get(0).getPayNo(), latticeOrderItemList.get(0).getHierarchy(), latticeOrderItemList.get(0).getFreightLane()));
                String re_status_key = String.format(RedisKey.VENDING_MACHINE_RE_STATUS, device.getDeviceNo(), order.getOutTradeNo());
                redisCacheTemplate.opsForValue().set(re_status_key, 1, 1000 * systemConfig.getOnLineInsertCoinNotNoticeTime(), TimeUnit.SECONDS);
                log.info("支付完成回调处理格子机:payNo{},hierarchy:{},freightLane:{},command:{}", latticeOrderItemList.get(0).getPayNo(), latticeOrderItemList.get(0).getHierarchy(), latticeOrderItemList.get(0).getFreightLane(), command);
            } else {
                // 这里有一个问题，就是如果操作30个商品，洋宇那边会少出，不过一般不会出30个这么夸张，所以不管
                if (orderItemList.size() > 0) {
                    command = PositiveDataFrameCMD.penetrate(VendmachPositiveDataFrameCMD.shipment(device.getDeviceNo(), order.getPayNo(), orderItemList));
                    bool = false;
                }
                if (latticeOrderItemList.size() > 0) {
                    if (bool) {
                        command = PositiveDataFrameCMD.penetrate(VendmachPositiveDataFrameCMD.LatticeShipmentTestNew(device.getDeviceNo(), order.getPayNo(), latticeOrderItemList, LatticeShipmentTestNewCmdEnum.SHIPPING.getCode()));
                    } else {
                        // 发起延时mq，设备不能同时发起2笔订单
                        Integer time = latticeOrderItemList.size() * 3200;
                        delayMap.put("cmd", "02");
                        delayMap.put("payNo", order.getPayNo());
                        delayMap.put("deviceTypeId", DeviceTypeEnum.OPEN_DOOR_VENDING_MACHINE.getCode().toString());
                        delayMap.put("deviceNo", device.getDeviceNo());
                        delayMap.put("orderItemList", JSON.toJSONString(latticeOrderItemList));
                        rabbitProducer.sendMotorDetectionEndLazyQueue(delayMap, time);

                    }
                }
            }
//            if(DeviceTypeEnum.VENDING_MACHINE.getCode().equals(order.getDeviceTypeId())){
//                redisCacheTemplate.opsForValue().set("pay"+DeviceTypeEnum.VENDING_MACHINE.getCode()+order.getOrderNo(),device.getDeviceNo(), 60, TimeUnit.SECONDS);
//            }
            boolean sendResult;
            if (device.getIsBluetooth()) {
                String key = String.format(RedisKey.BLUETOOTH_RE_SHIPPING, device.getDeviceNo(), order.getOutTradeNo());
                redisCacheTemplate.opsForValue().set(key, order.getId(), 20, TimeUnit.MINUTES);
                command = VendmachPositiveDataFrameCMD.LatticeShipmentTestNew(device.getDeviceNo(), order.getPayNo(), latticeOrderItemList, LatticeShipmentTestNewCmdEnum.SHIPPING.getCode());
                sendResult = blueToothPubService.pub(command, device.getDeviceNo(), "client_" + order.getMemberId());
            } else {
                sendResult = pubService.pub(command, device.getDeviceNo(), productKey, device.getIsBluetooth());
            }
            if (!sendResult) {
                errorLogCommonService.writerInfoErrorLog("售货机指令发送失败" + command, order);
                return;
            }
            if(!StringUtils.isEmpty(device.getPayLimitTime()) && device.getPayLimitTime()>0){
                rabbitProducer.sendVendingMachineReplayLazyQueue(DelayConstants.VENDING_MACHINE, order, 1000 * device.getPayLimitTime());
            }else{
                rabbitProducer.sendVendingMachineReplayLazyQueue(DelayConstants.VENDING_MACHINE, order, 1000 * systemConfig.getOnLineInsertCoinNotNoticeTime());
            }
        }else {

        }

        if (!StringUtils.isEmpty(order.getMemberId())) {
            merchantStoreService.setMemberRisk(order.getMemberId(), order.getMerchantStoreId(), order.getGmtPayment(), order.getTotalAmount());
        }
        // 被扫支付不需要更新
        if (!StringUtils.isEmpty(payNotice.getFunction()) && OrderFunctionEnum.REVERSE_SCAN.getStatus().compareTo(payNotice.getFunction()) != 0) {
            memberStoreBalanceService.updateOrderRecord(order);
        }
    }

    // 更新货道库存
    private void updateStock(DisplayRackItemVo displayRackItemVo, int deductedStock) {
        // 扣减库存
        displayRackItemVo.setStock(displayRackItemVo.getStock() - deductedStock);
        // 更新数据库中的货道库存信息
        DisplayRackItemDto updateDto = new DisplayRackItemDto();
        updateDto.setStock(displayRackItemVo.getStock());
        updateDto.setId(displayRackItemVo.getId());
        updateDto.setVersion(displayRackItemVo.getVersion());
        displayRackItemService.updateStockById(updateDto);
    }

    /**
     * 计算订单在各个级别的分润
     *
     * @param order
     */
    @Override
    public void orderHandlingCharge(Order order) {
        //TODO 商户费率固定0.6%，所以不用区分收款商户是平台商户还是商家自有商户，如果商户费率不固定才需要区分
        //获取商户费率
        final MerchantStoreVo merchant = null;
        BigDecimal mFeeVal;
        if (MchTypeEnum.OFFLINE_COLLECTION_CODE.getCode().equals(order.getMchType())) {
            // 线下收款码费率
            log.info(order.getOutTradeNo() + "线下收款码费率");
            if (StringUtils.isEmpty(merchant.getOfflineCollectionCodeRate())) {
                log.info(order.getOutTradeNo() + "线下收款码费率为空时用默认费率");
                mFeeVal = merchant.getFeeValue();
            } else {
                log.info(order.getOutTradeNo() + "线下收款码费率不为空时用对应费率");
                mFeeVal = merchant.getOfflineCollectionCodeRate();
            }
        } else {
            log.info(order.getOutTradeNo() + "默认费率");
            mFeeVal = merchant.getFeeValue();
        }

        //计算商户支付手续费
        BigDecimal handlingCharge = SciCalUtils.sciCalToBD(mFeeVal.multiply(order.getTotalAmount()).doubleValue(), 2);
        order.setHandlingCharge(handlingCharge);
        order.setSettlementMoney(SciCalUtils.sciCalToBD(order.getTotalAmount().subtract(order.getHandlingCharge()).doubleValue(), 2));

        //获取订单所属机构信息
//            AgencyDto agency = agencyService.getUserAgencyByUserIdAndChannelType(order.getUserId(), order.getChannelType());
        // 根据设备号查询对应的机构信息
        AgencyDto agency = agencyService.getDeviceAgencyByDeviceNoAndChannelType(order.getDeviceNo(), order.getMerchantStoreId(), order.getChannelType());

        try {
            //TODO 改成获取机构在汇联对应支付公司机构费率，可能不同支付公司费率不一样
            //获取总机构信息及费率
            AgencyDto adminAgency = agencyService.getAgencyByIdAndChannelType(adminAgencyId, order.getChannelType());

            //TODO 改成从数据库表获取对应汇联成本费率
            //汇联成本手续费
            BigDecimal huilianFee = new BigDecimal("0.0021");
            BigDecimal huilianFee2 = SciCalUtils.sciCalToBD(huilianFee.multiply(order.getTotalAmount()), 2);
            BigDecimal huilianFee4 = SciCalUtils.sciCalToBD(huilianFee.multiply(order.getTotalAmount()), 4);

            //商户手续费
            BigDecimal merchantFee2 = SciCalUtils.sciCalToBD(mFeeVal.multiply(order.getTotalAmount()), 2);
            BigDecimal merchantFee4 = SciCalUtils.sciCalToBD(mFeeVal.multiply(order.getTotalAmount()), 4);

            //汇联分润比例
            BigDecimal partnerPro = new BigDecimal(1);
            //亏损情况， 商户手续费舍一 或 成本手续费进一，用亏损差额计算分润比例（无论是否分账逻辑一样）
            if (merchantFee2.compareTo(merchantFee4) < 0 || huilianFee2.compareTo(huilianFee4) > 0) {
                if (merchantFee2.compareTo(huilianFee2) <= 0) {
                    partnerPro = BigDecimal.ZERO;
                } else {
                    //商户手续费差(可正可负值)
                    BigDecimal merchantFeeDiff = merchantFee4.subtract(merchantFee2);
                    //成本手续费差
                    BigDecimal costFeeDiff = huilianFee4.subtract(huilianFee2);
                    //总手续费差
                    BigDecimal feeDiff = merchantFeeDiff.subtract(costFeeDiff);
                    if (feeDiff.compareTo(BigDecimal.ZERO) > 0) {
                        //原分润
                        BigDecimal commission = merchantFee2.subtract(huilianFee2);
                        partnerPro = SciCalUtils.sciCalToBD((commission.subtract(feeDiff)).divide(commission, 5, BigDecimal.ROUND_HALF_UP), 5);
                    }
                }
            }
            log.info(JSON.toJSONString(partnerPro));

            //平台成本手续费
            BigDecimal costFee2 = SciCalUtils.sciCalToBD(adminAgency.getFee().multiply(order.getTotalAmount()), 2);
            BigDecimal costFee4 = SciCalUtils.sciCalToBD(adminAgency.getFee().multiply(order.getTotalAmount()), 4);

            //平台分润比例
            BigDecimal pro = new BigDecimal(1);
            //亏损情况， 商户手续费舍一 或 成本手续费进一，用亏损差额计算分润比例
            if (merchantFee2.compareTo(merchantFee4) < 0 || costFee2.compareTo(costFee4) > 0) {
                if (merchantFee2.compareTo(costFee2) <= 0) {
                    pro = BigDecimal.ZERO;
                } else {
                    //商户手续费差(可正可负值)
                    BigDecimal merchantFeeDiff = merchantFee4.subtract(merchantFee2);
                    //成本手续费差
                    BigDecimal costFeeDiff = costFee4.subtract(costFee2);
                    //总手续费差
                    BigDecimal feeDiff = merchantFeeDiff.subtract(costFeeDiff);
                    if (feeDiff.compareTo(BigDecimal.ZERO) > 0) {
                        //原分润
                        BigDecimal commission = merchantFee2.subtract(costFee2);
                        pro = SciCalUtils.sciCalToBD((commission.subtract(feeDiff)).divide(commission, 5, BigDecimal.ROUND_HALF_UP), 5);
                    }
                }
            }
            log.info(JSON.toJSONString(pro));
            //有手续费才计算分润
            if (order.getHandlingCharge().compareTo(BigDecimal.ZERO) > 0 && pro.compareTo(BigDecimal.ZERO) > 0 && partnerPro.compareTo(BigDecimal.ZERO) > 0) {
                //查询顶级机构(总机构以下)
                AgencyDto topAgency = getTopAgency(agency, order.getChannelType());
                OrderCommission orderCommission = new OrderCommission();
                orderCommission.setLowerCommission(BigDecimal.ZERO);
                orderCommission.setRealCommission(BigDecimal.ZERO);
                orderCommission.setCommissionTotal(BigDecimal.ZERO);
                this.salIncome(mFeeVal, agency, topAgency, order, orderCommission, 0, pro, partnerPro);
            }

        } catch (Exception e) {
            log.error("计算分润出错:{}", e);
            errorLogCommonService.writerInfoException("计算分润出错", order, e);
        }
        //处理套餐佣金
        if (OrderStatusEnum.SUCCESS.getCode().equals(order.getStatus())) {
            OrderDto orderDto = null;
            try {
                //通过缓存获取订单是否抽佣
                final String key = String.format(RedisKey.ORDER_SKU_DEDUCTCOMMISSION_V2, order.getId(), LedgerOrderTypeEnum.ORDER.getCode());
                final BigDecimal shareMoney = (BigDecimal) redisCacheTemplate.opsForValue().get(key);
                if (!StringUtils.isEmpty(shareMoney)) {

                }
            } catch (Exception e) {
                e.printStackTrace();
                log.error("支付回调交易抽佣扣除余额出错:{}", e.getMessage());
                errorLogCommonService.writerInfoException("支付回调交易抽佣扣除余额出错", orderDto, e);
            }

            try {
                //套餐佣金给代理返佣
                if (orderDto != null && orderDto.getIsDeductCommission() != null && orderDto.getIsDeductCommission() == 1) {
                    OrderCommission orderCommission = new OrderCommission();
                    orderCommission.setLowerCommission(BigDecimal.ZERO);
                    orderCommission.setRealCommission(BigDecimal.ZERO);
                    orderCommission.setCommissionTotal(BigDecimal.ZERO);
                    this.salIncomeSku(orderDto.getDeductCommission(), agency, order, orderCommission, 0, merchant);
                }
            } catch (Exception e) {
                e.printStackTrace();
                log.error("交易抽佣计算分润出错:{}", e);
                errorLogCommonService.writerInfoException("交易抽佣计算分润出错", orderDto, e);
            }
        } else {
            try {
                if (order.getIsDeductCommission() == 1) {

                }
            } catch (Exception e) {
                log.error("退款成功，套餐佣金处理出错:{}", e);
                errorLogCommonService.writerInfoException("退款成功，套餐佣金处理出错", order, e);
            }

        }
        // 修改订单状态等等
        this.updateOrder(order);

        OrderItem orderItem = new OrderItem();
        orderItem.setOrderId(order.getId());
        orderItem.setStatus(OrderItemStatusEnum.SUCCESS.getCode());
        orderItemService.updateStatus(orderItem);

    }

    private void salIncomeSku(BigDecimal deductCommission, AgencyDto agency, Order order, OrderCommission lowerOrderCommission, int i, MerchantStoreVo merchantStoreVo) {
        //计算平台分润
        if (agency.getId().equals(adminAgencyId)) {
            this.salPlatformIncomeSku(deductCommission, agency, order, lowerOrderCommission);
            return;
        }

        //计算机构分润
        OrderCommission agencyOrderCommission = new OrderCommission();
        agencyOrderCommission = this.salUserIncomeSku(deductCommission, agency, order, lowerOrderCommission, merchantStoreVo);

        //判断是否还有上级机构
        if (i < 3) {
            AgencyDto parentAgency = agencyService.getAgencyByIdAndChannelType(agency.getParentId(), order.getChannelType());
            if (parentAgency != null) {
                this.salIncomeSku(deductCommission, parentAgency, order, agencyOrderCommission, ++i, merchantStoreVo);
            }
        } else if (i == 3) {
            AgencyDto adminAgency = agencyService.getAgencyByIdAndChannelType(adminAgencyId, order.getChannelType());
            this.salPlatformIncomeSku(deductCommission, adminAgency, order, agencyOrderCommission);
            return;
        }
    }

    private void salPlatformIncomeSku(BigDecimal deductCommission, AgencyDto agency, Order order, OrderCommission lowerOrderCommission) {
        OrderCommission orderCommission = new OrderCommission();

        //平台套餐没有成本，deductCommission佣金都是利润
        orderCommission.setCommissionTotal(deductCommission);
        orderCommission.setRealCommission(SciCalUtils.sciCalToBD(orderCommission.getCommissionTotal().subtract(lowerOrderCommission.getCommissionTotal()), 4));
        orderCommission.setLowerCommission(lowerOrderCommission.getCommissionTotal());
        orderCommission.setUserId(agency.getUserId());
        orderCommission.setOrderId(order.getId());
        orderCommission.setRate(BigDecimal.ZERO);
        orderCommissionService.insert(orderCommission);
    }

    private OrderCommission salUserIncomeSku(BigDecimal deductCommission, AgencyDto agency, Order order, OrderCommission lowerOrderCommission, MerchantStoreVo merchantStoreVo) {
        //计算机构负责人的分润
        OrderCommission orderCommission = new OrderCommission();
        if (adminAgencyId.equals(agency.getId())) {
            AgencyDto adminAgency = agencyService.getAgencyByIdAndChannelType(adminAgencyId, order.getChannelType());
            this.salPlatformIncomeSku(deductCommission, adminAgency, order, lowerOrderCommission);
            return orderCommission;
        }

        //计算每级分润
        BigDecimal feeRate = BigDecimal.ZERO;
        if (MchTypeEnum.DOUYIN_GROUP_PURCHASE.getCode().equals(order.getMchType())) {
            feeRate = merchantStoreVo.getTiktokRate();
        } else if (MchTypeEnum.MEITUAN_GROUP_PURCHASE.getCode().equals(order.getMchType())) {
            feeRate = merchantStoreVo.getMeiTuanRate();
        }
        //费率差
        BigDecimal feeDiff = feeRate.subtract(agency.getFee());
        BigDecimal commissionTotal = BigDecimal.ZERO;
        if (feeDiff.compareTo(BigDecimal.ZERO) == 1) {
            //分润比例
            BigDecimal ratio = feeDiff.divide(feeRate);
            commissionTotal = SciCalUtils.sciCalToBD(deductCommission.multiply(ratio), 4);
        }

        orderCommission.setCommissionTotal(commissionTotal); // 总分润
        orderCommission.setLowerCommission(SciCalUtils.sciCalToBD(lowerOrderCommission.getCommissionTotal(), 4));   //下级的分润
        orderCommission.setRealCommission(SciCalUtils.sciCalToBD(orderCommission.getCommissionTotal().subtract(orderCommission.getLowerCommission()), 4));//实得分润
        orderCommission.setOrderId(order.getId());
        orderCommission.setUserId(agency.getUserId());
        orderCommission.setRate(agency.getFee());

        orderCommissionService.insert(orderCommission);
        return orderCommission;
    }


    @Override
    public OrderDto getById(Long orderId) {
        return orderDao.getById(orderId);
    }

    @Override
    public Order findById(Long orderId) {
        return orderDao.findById(orderId);
    }

    @Override
    public Order findOldOrder(Long orderId) {
        return orderDao.findOldOrder(orderId);
    }

    @Override
    public Integer updateStatusById(OrderDto order) {
        return orderDao.updateStatusById(order);
    }

    /**
     * 退款
     *
     * @param orderRefundDto
     * @return
     */
    @Override
    public int orderRefund(OrderRefundDto orderRefundDto) {
        Map<String, Object> form = new HashMap<>();
        form.put("HlMerchantId", orderRefundDto.getMerchantId());
        form.put("OutTradeNo", orderRefundDto.getOutTradeNo());
        form.put("OutRefundNo", orderRefundDto.getOutRefundNo());
        form.put("RefundAmount", orderRefundDto.getRefundAmount().multiply(new BigDecimal("100")).setScale(0, BigDecimal.ROUND_HALF_UP));
        form.put("RefundReason", orderRefundDto.getFailReason());
        String param = HttpUtils.format(agencyConfig, form, FunctionEnum.ORDER_REFUND);
        String response;
        try {
            response = HttpsMain.httpsReq(MiddlewareConfig.orderUrl, param);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("请求退款接口异常！");
            return 0;
        }
        log.info("请求响应结果{}", response);
        //延签并返回map值
        final Map<String, Object> result = HttpUtils.getResultData(response);
        final String status = (String) result.get("status");
        final String code = (String) result.get("code");
        if (status.equals(RequestStatus.SUCCESS.getCode()) && code.equals(RequestStatus.SUCCESS_CODE.getCode())) {
            log.info("申请退款成功后发送MQ：{}", System.currentTimeMillis());
            CorrelationData correlationData = new CorrelationData(orderRefundDto.getOutRefundNo());
            rabbitTemplate.convertAndSend("iotBox-order-Refund", "iotBox-order-Refund.iotBoxOrderRefund", orderRefundDto, correlationData);
            return 1;
        } else {
            throw new ControllerException((String) result.get("msg"));
        }
    }

    @Override
    public int updateOrderShoutStatus(Order order) {
        return orderDao.updateShoutStatus(order);
    }

    /**
     * 计算分润
     *
     * @param mFeeVal             商家费率
     * @param agency              商家所属机构
     * @param topAgency           总机构外，顶级机构
     * @param order               订单记录
     * @param lowerOderCommission 下级分润
     * @param i                   递归次数
     * @param pro                 平台分润比例
     * @param partnerPro          汇联分润比例
     */
    private void salIncome(BigDecimal mFeeVal, AgencyDto agency, AgencyDto topAgency, Order order, OrderCommission lowerOderCommission, int i, BigDecimal pro, BigDecimal partnerPro) {

        //计算平台分润
        if (agency.getId().equals(adminAgencyId)) {
            this.salPlatformIncome(mFeeVal, agency, order, lowerOderCommission, partnerPro);
            return;
        }

        //计算机构分润
        OrderCommission agencyOrderCommission = new OrderCommission();
        agencyOrderCommission = salUserIncome(mFeeVal, agency, topAgency, order, lowerOderCommission, pro, partnerPro);

        //判断是否还有上级机构
        if (i < 3) {
            AgencyDto parentAgency = agencyService.getAgencyByIdAndChannelType(agency.getParentId(), order.getChannelType());
            if (parentAgency != null) {
                this.salIncome(mFeeVal, parentAgency, topAgency, order, agencyOrderCommission, ++i, pro, partnerPro);
            }
        } else if (i == 3) {
            AgencyDto adminAgency = agencyService.getAgencyByIdAndChannelType(adminAgencyId, order.getChannelType());
            this.salPlatformIncome(mFeeVal, adminAgency, order, agencyOrderCommission, partnerPro);
            return;
        }
    }

    /**
     * 计算机构负责人分润
     *
     * @param mFeeVal              商家费率
     * @param agency               商家所属机构
     * @param topAgency            总机构外，顶级机构
     * @param order                订单记录
     * @param lowerOrderCommission 下级分润
     * @param pro                  平台分润比例
     * @param partnerPro           汇联分润比例
     * @return 当前机构负责人分润
     */
    private OrderCommission salUserIncome(BigDecimal mFeeVal, AgencyDto agency, AgencyDto topAgency, Order order, OrderCommission lowerOrderCommission, BigDecimal pro, BigDecimal partnerPro) {
        //计算机构负责人的分润
        OrderCommission orderCommission = new OrderCommission();
        if (adminAgencyId.equals(agency.getId())) {
            AgencyDto adminAgency = agencyService.getAgencyByIdAndChannelType(adminAgencyId, order.getChannelType());
            salPlatformIncome(mFeeVal, adminAgency, order, lowerOrderCommission, partnerPro);
            return orderCommission;
        }
        //有费率差才有分润
        if (mFeeVal.compareTo(agency.getFee()) > 0) {
            orderCommission.setCommissionTotal(SciCalUtils.sciCalToBD((mFeeVal.subtract(agency.getFee())).multiply(order.getTotalAmount()).multiply(pro).multiply(partnerPro), 4)); // 总分润
            orderCommission.setLowerCommission(SciCalUtils.sciCalToBD(lowerOrderCommission.getCommissionTotal(), 4));   //下级的分润
            orderCommission.setRealCommission(SciCalUtils.sciCalToBD(orderCommission.getCommissionTotal().subtract(orderCommission.getLowerCommission()), 4));//实得分润
        } else {
            orderCommission.setCommissionTotal(BigDecimal.ZERO);
            orderCommission.setLowerCommission(BigDecimal.ZERO);
            orderCommission.setRealCommission(BigDecimal.ZERO);
        }
        orderCommission.setOrderId(order.getId());
        orderCommission.setUserId(agency.getUserId());
        orderCommission.setRate(agency.getFee());

        orderCommissionService.insert(orderCommission);
        return orderCommission;
    }

    /**
     * 计算平台分润
     *
     * @param mFeeVal              商家费率
     * @param agency               机构信息
     * @param order                订单信息
     * @param lowerOrderCommission 下级分润
     * @param partnerPro           汇联分润比例
     */
    private void salPlatformIncome(BigDecimal mFeeVal, AgencyDto agency, Order order, OrderCommission lowerOrderCommission, BigDecimal partnerPro) {
        OrderCommission orderCommission = new OrderCommission();
//        if (order.getBaseHandlingCharge().compareTo(salCostFee(order, feeType)) <= 0) {
//            order.setTotalCommission(new BigDecimal("0"));
//        } else {
//            }

        //汇联给的总分润
        order.setTotalCommission(SciCalUtils.sciCalToBD((mFeeVal.subtract(agency.getFee())).multiply(order.getTotalAmount()).multiply(partnerPro), 4));

        orderCommission.setCommissionTotal(order.getTotalCommission());
        orderCommission.setRealCommission(SciCalUtils.sciCalToBD(orderCommission.getCommissionTotal().subtract(lowerOrderCommission.getCommissionTotal()), 4));
        orderCommission.setLowerCommission(lowerOrderCommission.getCommissionTotal());
        orderCommission.setUserId(agency.getUserId());
        orderCommission.setOrderId(order.getId());
        orderCommission.setRate(agency.getFee());
        orderCommissionService.insert(orderCommission);
    }

    /**
     * 获取除总机构外，顶级机构
     *
     * @param agency
     * @return
     */
    @Override
    public AgencyDto getTopAgency(AgencyDto agency, String channelType) {
        if (agency.getParentId().equals(adminAgencyId) || agency.getParentId() == 0) {
            return agency;
        } else {
            AgencyDto topAgency = agencyService.getAgencyByIdAndChannelType(agency.getParentId(), channelType);
            return getTopAgency(topAgency, channelType);
        }
    }

    @Override
    public OrderVo findOrderByPayNo(String payNo, String deviceNo) {
        return orderDao.findOrderByPayNo(payNo,deviceNo);
    }
}
